package org.example.binding;

import lombok.Data;
import org.example.config.Configuration;
import org.example.mapping.MappedStatement;
import org.example.mapping.SqlCommandType;
import org.example.reflection.ParamNameResolver;
import org.example.session.SqlSession;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.IllegalFormatCodePointException;
import java.util.Map;

public class MapperMethod {
  private final Class<?> mapperInterface;
  private final Method method;
  private final Configuration config;
  private final SqlSession sqlSession;
  private final SqlCommand sqlCommand;
  private final MethodSignature methodSignature;
  private final ParamNameResolver paramNameResolver;

  public MapperMethod(Class<?> mapperInterface, Method method, SqlSession sqlSession) {
    this.mapperInterface = mapperInterface;
    this.method = method;
    this.config = sqlSession.getConfiguration();
    this.sqlSession = sqlSession;
    this.sqlCommand = new SqlCommand(config,mapperInterface,method);
    this.methodSignature = new MethodSignature(method);
    this.paramNameResolver = new ParamNameResolver(config, method);
  }

  public Object execute(Object[] args) {
    Object result = null;
    //返回类型
    switch (sqlCommand.getType()){
      case SELECT:
        //查询单个对象
        if(methodSignature.returnsOne){
          Object arg = convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(sqlCommand.getName(),arg);
        }
        break;
    }
    return result;
  }
  public Object convertArgsToSqlCommandParam(Object[] args) {
    return paramNameResolver.getNamedParams(args);
  }


  @Data
  public static class MethodSignature {
    private final boolean returnsMany;
    private final boolean returnsVoid;
    private final Class<?> returnType;
    private final boolean returnsMap;
    private final boolean returnsOne;

    public MethodSignature(Method method) {
      this.returnType = method.getReturnType();
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = Collection.class.isAssignableFrom(this.returnType);
      this.returnsMap = Map.class.isAssignableFrom(method.getReturnType());
      this.returnsOne = (!returnsMany && !returnsMap && !returnsVoid);
    }
  }
  @Data
  public static class SqlCommand {

    private final String name;
    private final SqlCommandType type;

    public SqlCommand(Configuration config, Class<?> mapperInterface, Method method) {
      MappedStatement mappedStatement = config.getMappedStatements(mapperInterface, method.getName());
      if (mappedStatement == null) {
        throw new IllegalStateException("No mapped statement found for " + mapperInterface.getName() + "." + method.getName());
      }
      this.name = mappedStatement.getId();
      this.type = mappedStatement.getSqlCommandType();
    }
  }
}